package org.richin.support.web.struts;

import java.io.Serializable;
import java.lang.reflect.Field;
import java.util.List;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.beanutils.ConvertUtils;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;
import org.apache.struts.action.ActionMessages;
import org.richin.lang.util.StringUtils;
import org.richin.reflection.util.BeanUtils;
import org.richin.reflection.util.ReflectUtils;
import org.richin.support.biz.BusinessException;
import org.richin.support.biz.EntityManager;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.ReflectionUtils;


@SuppressWarnings("unchecked")
public abstract class BaseCRUDAction<T, M extends EntityManager> extends StrutsAction implements InitializingBean {
	/**Action所管理的Entity类型*/
	protected Class<T> entityClass;
	/**Action所管理的Entity的主键类型*/
	protected Class<?> idClass;
	/**Action所管理的Entity的主键名*/
	protected String idName;
	/**Action管理Entity所用的manager*/
	private M entityManager;

	/** 取得entityClass的函数. JDK1.4不支持泛型的子类可以抛开Class<T> entityClass,重载此函数达到相同效果。*/
	protected Class<T> getEntityClass() {
		return entityClass;
	}

	public BaseCRUDAction() {
		entityClass = ReflectUtils.getSuperClassGenricType(getClass());
	}
	/**
	 * 获得EntityManager类进行CRUD操作,可以在子类重载.
	 */
	protected abstract M getEntityManager();
	/**
	 * Init回调函数,初始化一系列泛型参数.
	 */
	public void afterPropertiesSet() {
		// 根据T,反射获得entityClass
		entityClass = ReflectUtils.getSuperClassGenricType(getClass());
		log.debug("entityClass:" + entityClass);
		// 根据M,反射获得符合M类型的manager
		List<Field> fields = BeanUtils.getFieldsByType(this, ReflectUtils.getSuperClassGenricType(getClass(), 1));
		Assert.isTrue(fields.size() == 1, "subclass's has not only one entity manager property.");
		try {
			entityManager = (M) BeanUtils.forceGetProperty(this, fields.get(0).getName());
			Assert.notNull(entityManager, "subclass not inject manager to action sucessful.");
		} catch (Exception e) {
			ReflectionUtils.handleReflectionException(e);
		}

		// 反射获得entity的主键类型
		try {
			idName = entityManager.getIdName();
			idClass = BeanUtils.getPropertyType(entityClass, idName);
		} catch (Exception e) {
			ReflectionUtils.handleReflectionException(e);
		}
	}

	/**
	 * 显示Welcome页的Action函数. 默认跳转到{@link #list(ActionMapping,ActionForm,HttpServletRequest,HttpServletResponse) }
	 */
	@Override
	public ActionForward index(ActionMapping mapping, ActionForm form, HttpServletRequest request,
			HttpServletResponse response)throws Exception  {
		return list(mapping, form, request, response);
	}

	/**
	 * 列出所有对象的Action函数.
	 */
	public abstract ActionForward list(ActionMapping mapping, ActionForm form, HttpServletRequest request,
			HttpServletResponse response)throws Exception;

	/**
	 * 显示新建对象Form的Action函数. 默认跳到{@link #edit(ActionMapping,ActionForm,HttpServletRequest,HttpServletResponse)}}
	 */
	public ActionForward create(ActionMapping mapping, ActionForm form, HttpServletRequest request,
			HttpServletResponse response)throws Exception {
		return edit(mapping, form, request, response);
	}

	/**
	 * 显示修改对象Form的Action函数.
	 */
	public ActionForward edit(ActionMapping mapping, ActionForm form, HttpServletRequest request,
			HttpServletResponse response)throws Exception  {
		//防止重复提交的token
		saveToken(request);
		T entity = null;

		// 如果是修改操作，id!=null
		if (request.getParameter(getIdName()) != null) {
			entity = doGetEntity(form, request);
			if (entity == null) {
				saveError(request, "entity.missing");
				return mapping.findForward(LIST);
			}
		} else {
			try {
				entity = entityClass.newInstance();
			} catch (InstantiationException e) {
				log.error(e);
			} catch (IllegalAccessException e) {
				log.error(e);
			}
		}

		initForm(form, request, entity);
		refrenceData(request);
		return mapping.findForward(EDIT);
	}

	/**
	 * 查看业务对象（不能修改）的Action函数.
	 */
	public ActionForward view(ActionMapping mapping, ActionForm form, HttpServletRequest request,
			HttpServletResponse response)throws Exception  {
		Assert.notNull(request,"request is null");
		T entity = doGetEntity(form, request);
		if (entity == null) {
			saveError(request, "entity.missing");
			return mapping.findForward(LIST);
		}
		request.setAttribute(getEntityName(), entity);
		refrenceData(request);
		return mapping.findForward(VIEW);
	}

	/**
	 * 保存对象的Action函数.
	 */
	public ActionForward save(ActionMapping mapping, ActionForm form, HttpServletRequest request,
			HttpServletResponse response)throws Exception  {
		ActionForward errorActionForward=doSaveBefore(mapping, form, request, response);
		if(errorActionForward!=null)
			return errorActionForward;
		T entity;
		// 如果是修改操作，id is not blank
		if (StringUtils.isNotBlank(request.getParameter(getIdName()))) {
			entity = doGetEntity(form, request);
			if (entity == null) {
				saveError(request, "entity.missing");
				return mapping.findForward(LIST);
			}
		} else { // 否则为新增操作
			entity = doNewEntity(form, request);
		}
		try {
			// 将lazyform内容绑定到entity
			initEntity(form, request, entity);
			doSaveEntity(form, request, entity);
			savedMessage(request, entity);
		} catch (BusinessException e) {
			log.error(e.getMessage(), e);
			saveDirectlyError(request, e.getMessage());
			refrenceData(request);
			return mapping.findForward(EDIT);
		}
		return mapping.findForward(SUCCESS);
	}
	/**保存前的一些操作,主要为isCancelled() 判断是否重复提交,验证表单*/
	protected ActionForward doSaveBefore(ActionMapping mapping, ActionForm form, HttpServletRequest request,
			HttpServletResponse response)throws Exception  {
		if (isCancelled(request))
			return list(mapping, form, request, response);
		if (!isTokenValid(request)) {
			saveDirectlyError(request, "重复提交");
			return mapping.findForward(LIST);
		}
		resetToken(request);

		// run validation rules on this form
		ActionMessages errors = form.validate(mapping, request);
		if (!errors.isEmpty()) {
			saveErrors(request, errors);
			refrenceData(request);
			return mapping.findForward(EDIT);
		}
		return null;
	}

	/**
	 * 删除单个对象的Action函数.
	 */
	public ActionForward delete(ActionMapping mapping, ActionForm form, HttpServletRequest request,
			HttpServletResponse response)throws Exception  {
		try {
			doDeleteEntity(form, request);
			deletedMessage(request);
		} catch (Exception e) {
			saveDirectlyError(request, e.getMessage());
		}
		return mapping.findForward(SUCCESS);
	}
	/**
	 * 保存Form表单时,初始化Entity对象的属性.
	 */
	protected void initEntity(ActionForm form, HttpServletRequest request, T entity) {
		bindEntity(form, entity);
		onInitEntity(form, request, entity);
	}

	/**
	 * 显示Form表单时，初始化Form对象的属性.
	 */
	protected void initForm(ActionForm form, HttpServletRequest request, T entity) {
		bindForm(form, entity);
		onInitForm(form, request, entity);
	}



	/**
	 * 新建业务对象的函数.
	 */
	protected T doNewEntity(ActionForm form, HttpServletRequest request) {
		T entity = null;
		try {
			entity = getEntityClass().newInstance();
		} catch (Exception e) {
			log.error("Can't new Instance of entity.", e);
		}
		return entity;
	}

	/**
	 * 从数据库获取业务对象的函数.
	 */
	protected T doGetEntity(ActionForm form, HttpServletRequest request) {
		Serializable id = getEntityId(request);
		log.debug(id);
		return (T) getEntityManager().get(id);
	}

	/**
	 * 保存业务对象的函数.
	 */
	protected void doSaveEntity(ActionForm form, HttpServletRequest request, T entity) {
		getEntityManager().save(entity);
	}

	/**
	 * 删除业务对象的函数.
	 */
	protected void doDeleteEntity(ActionForm form, HttpServletRequest request) {
		Serializable id = getEntityId(request);
		getEntityManager().delete(id);
	}

	/**
	 * form与list界面所需的参考对象注入.如categoryList,在子类重载.
	 */
	protected void refrenceData(HttpServletRequest request) {
	}

	/**
	 * 显示Form表单时的回调函数.为Form对象添加更多属性,在子类重载.
	 */
	protected void onInitForm(ActionForm form, HttpServletRequest request, T entity) {
	}

	/**
	 * 保存Form表单时的回调函数.为业务对象添加更多属性，在子类重载.
	 */
	protected void onInitEntity(ActionForm form, HttpServletRequest request, T entity) {
	}

	/**
	 * 生成保存成功的信息.
	 */
	protected void savedMessage(HttpServletRequest request, T entity) {
		saveMessage(request, "entity.saved");
	}

	/**
	 * 生成删除成功的信息.
	 */
	protected void deletedMessage(HttpServletRequest request) {
		saveMessage(request, "entity.deleted");
	}

	/**
	 * 获取所管理的对象名.
	 * 首字母小写，如"user".
	 */
	protected String getEntityName() {
		return StringUtils.uncapitalize(ClassUtils.getShortName(getEntityClass()));
	}

	/**
	 * 获取所管理的对象列表名.
	 * 首字母小写，如"users".
	 */
	protected String getEntityListName() {
		return StringUtils.uncapitalize(ClassUtils.getShortName(getEntityClass())) + "s";
	}

	/**
	 * 从request中获得Entity的id，并判断其有效性.
	 */
	private Serializable getEntityId(HttpServletRequest request) {
		Assert.notNull(request,"request is null...");
		String idString = request.getParameter(getIdName());
		try {
			return (Serializable) ConvertUtils.convert(idString, getIdClass());
		} catch (NumberFormatException e) {
			throw new IllegalArgumentException("Wrong when get id from request");
		}
	}

	private Class<?> getIdClass() {
		idClass=ReflectUtils.getSuperClassGenricType(entityClass,0);
		return idClass;
	}

	private String getIdName() {
			if(StringUtils.isEmpty(idName))
				idName=getEntityManager().getIdName();
		return idName;
	}
}
